#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
@File   : DiskApi.py
@Time : 2024/12/18 14:04
@Author: Wangwc
@Describe:  硬盘管理接口
"""
import os
import socket
import subprocess
import time

import paramiko
import requests

from utils.requests_tools import HttpRequest, check_response, retry_func
from utils.login import Login
from commons.logger import log
from commons.fake_data import Fake
from utils.ssh_tools import create_ssh_client_as_root, create_raid_with_shell

# TODO 当前模块的配置文件名称，配置在config目录下
config_name = 'cloud.ini'

assert_message = {'code': 200, 'msg': 'success'}
login = Login(config_name=config_name)


class DiskApi:

    def __init__(self, u_token,configname=config_name):
        self.http = HttpRequest(configname, u_token=u_token)

    @check_response(ext="data", check=assert_message)
    def get_cron_tasks(self):
        """
        获取定时任务列表
        :return: 组件列表
        """
        log.debug("开始执行获取定时任务列表操作")
        path = "/ugreen/v1/storage/overview/cron/tasks"
        try:
            response = self.http.get(path)
            return response
        except Exception as e:
            log.error(f"在获取定时任务列表过程中出现异常，异常信息: {e}")
            raise

    @check_response(ext="data.result", check=assert_message)
    def get_volume_iops(self, type=1):
        """
        获取存储空间读写性能
        :param type:性能指标类型，1：传输性能、2：IOPS、3：利用率
        :return:
        """
        log.debug("开始执行获取存储空间读写性能操作")
        path = "/ugreen/v1/storage/volume/iops"
        try:
            parms = {"type": type, 'interval': 5}
            response = self.http.get(path, params=parms)
            return response
        except Exception as e:
            log.error(f"在获取存储空间读写性能过程中出现异常，异常信息: {e}")

    @check_response(ext="data.result", check=assert_message)
    def get_disk_iops(self, type=1):
        """
        获取硬盘读写性能
        :param type:性能指标类型，1：传输性能、2：IOPS、3：利用率
        :return:
        """
        log.debug("开始执行获取硬盘读写性能操作")
        path = "/ugreen/v1/storage/disk/iops"
        try:
            parms = {"type": type, 'interval': 5}
            response = self.http.get(path, params=parms)
            return response
        except Exception as e:
            log.error(f"在获获取硬盘读写性能过程中出现异常，异常信息: {e}")

    @check_response(ext="data.result", check=assert_message)
    def get_app_pool_list(self, pool_name):
        """
        获取存储池安装的app列表
        :param pool_name:存储池名称 示例："pool1"
        :return:
        """
        log.debug("开始执行获取存储池安装的app列表操作")
        path = "/ugreen/v1/app/pool/list"
        data = {"pool": pool_name}
        try:
            response = self.http.post(path, json=data)
            return response
        except Exception as e:
            log.error(f"在获取存储池安装的app列表过程中出现异常，异常信息: {e}")

    @check_response(ext="data.result", check=assert_message)
    def get_pool_list(self):
        """
        获取存储池列表信息
        :return:
        """
        log.debug("开始执行获取存储空间状态信息操作")
        path = "/ugreen/v1/storage/pool/list"
        try:
            response = self.http.get(path)
            return response
        except Exception as e:
            log.error(f"在获取存储空间状态信息过程中出现异常，异常信息: {e}")

    @check_response(ext="data.result", check=assert_message)
    def get_disk_list(self):
        """
        获取所有内置磁盘信息
        :return:硬盘信息列表
        """
        log.debug("开始执行获取所有内置磁盘信息操作")
        path = "/ugreen/v2/storage/disk/list"
        try:
            response = self.http.get(path)
            return response
        except Exception as e:
            log.error(f"在获取所有内置磁盘信息过程中出现异常，异常信息: {e}")

    @check_response(ext="data.result", check=assert_message)
    def get_disk_vars(self):
        """
        获取所有内置磁盘温度
        :return:硬盘温度列表
        """
        log.debug("开始执行获取所有内置磁盘温度操作")
        path = "/ugreen/v1/storage/disk/vars"
        try:
            response = self.http.get(path)
            return response
        except Exception as e:
            log.error(f"在获取所有内置磁盘温度过程中出现异常，异常信息: {e}")

    @check_response(ext="data", check=assert_message)
    def get_disk_slotnum(self):
        """
        获取机器内置nvme、sata插槽数
        :return: nvme sata
        """
        log.debug("开始执行获取机器内置nvme、sata插槽数")
        path = "/ugreen/v1/storage/disk/slotnum"
        try:
            response = self.http.get(path)
            return response
        except Exception as e:
            log.error(f"在获取机器内置nvme、sata插槽数过程中出现异常，异常信息: {e}")

    @check_response(ext="data.result", check=assert_message)
    def get_disk_cron_list(self):
        """
        获取硬盘检测计划
        :return: 硬盘检测计划列表
        """
        log.debug("开始执行获取硬盘检测计划")
        path = "/ugreen/v1/storage/disk/cron/list"
        try:
            response = self.http.get(path)
            return response
        except Exception as e:
            log.error(f"在获取硬盘检测计划过程中出现异常，异常信息: {e}")

    @check_response(ext="data", check=assert_message)
    def add_disk_cron_task(self, name, disks, first_run_datetime, type=0, enable=True, ihm_enable=False, interval=1,
                           interval_unit=4):
        """
        添加硬盘检测计划
        :param: name：计划名称
        :param: disk：检测硬盘列表   ["/dev/sdb", "/dev/sda"]
        :param: type：检测类型 0：快速检测、1：完整检测
        :param: enable：是否启用 0：禁用、1：启用
        :param: interval：检测间隔,3个月1次时为3；其他为1
        :param: interval_unit：检测间隔单位 4：天、6：周、5：月
        :return: nvme sata
        """
        log.debug("开始执行添加硬盘检测计划")
        path = "/ugreen/v1/storage/disk/cron/add"
        request_data = {"name": name, "disks": disks, "smart": {"enable": enable, "type": type},
                        "ihm": {"enable": ihm_enable},
                        "schedule": {"interval": interval, "interval_unit": interval_unit,
                                     "first_run_datetime": first_run_datetime}}
        try:
            response = self.http.post(path, json=request_data)
            return response
        except Exception as e:
            log.error(f"在添加硬盘检测计划过程中出现异常，异常信息: {e}")

    @check_response(ext="data", check=assert_message)
    def edit_disk_cron_task(self, name, disks, id, first_run_datetime, type=0, enable=True, ihm_enable=False,
                            interval=1, interval_unit=4):
        """
        编辑硬盘检测计划
        :param: name：计划名称
        :param: disk：检测硬盘列表   ["/dev/sdb", "/dev/sda"]
        :param: type：检测类型 0：快速检测、1：完整检测
        :param: enable：是否启用 0：禁用、1：启用
        :param: interval：检测间隔,3个月1次时为3；其他为1
        :param: interval_unit：检测间隔单位 4：天、6：周、5：月
        :return: nvme sata
        """
        log.debug("开始执行添加硬盘检测计划")
        path = "/ugreen/v1/storage/disk/cron/add"
        request_data = {"name": name, "disks": disks,
                        "smart": {"enable": enable, "type": type}, "ihm": {"enable": ihm_enable},
                        "schedule": {"interval": interval, "interval_unit": interval_unit,
                                     "first_run_datetime": first_run_datetime},
                        "cron_id": id}
        try:
            response = self.http.post(path, json=request_data)
            return response
        except Exception as e:
            log.error(f"在添加硬盘检测计划过程中出现异常，异常信息: {e}")

    @check_response(ext="data", check=assert_message)
    def delete_disk_cron_task(self, id):
        """
        删除硬盘检测计划
        :param: id：计划id
        :return:
        """
        log.debug("开始执行删除硬盘检测计划")
        path = "/ugreen/v1/storage/disk/cron/del"
        request_data = {"id": id}
        try:
            response = self.http.post(path, json=request_data)
            return response
        except Exception as e:
            log.error(f"在删除硬盘检测计划过程中出现异常，异常信息: {e}")

    @check_response(ext="data.available", check=assert_message)
    def get_pool_operate_disk(self, pool_name="pool1", operate="replace"):
        """
        获取存储池可以替换的硬盘信息
        :return: pool_name
        """
        log.debug("开始执行获取存储池可以替换的硬盘信息")
        path = "/ugreen/v1/storage/pool/operate/disks"
        params = {"poolName": pool_name, "operate": operate}
        try:
            response = self.http.get(path, params=params)
            return response
        except Exception as e:
            log.error(f"在获取存储池可以替换的硬盘信息过程中出现异常，异常信息: {e}")

    @check_response(ext="data.result", check=assert_message)
    def get_widget_list(self):
        """
        获取存储管理器组件列表
        :return: 组件列表
        """
        log.debug("开始执行获取存储管理器组件列表操作")
        path = "/ugreen/v1/storage/overview/widget"
        try:
            response = self.http.get(path)
            return response
        except Exception as e:
            log.error(f"在获取存储管理器组件列表过程中出现异常，异常信息: {e}")

    @check_response(ext="data", check=assert_message)
    def add_widget(self, type, flags):
        """
        添加存储管理器组件
        :param type: 组件类型  1：硬盘状态信息、2：存储空间状态信息、3：定时任务计划、4：硬盘性能监测、5：存储空间性能监测
        :param flags: 小组件配置 type=1:[1,2]、type=2:[0]、type=3:[0,1,2]、type=4:[0]、type=5:[0]
        :return:
        """
        log.debug("开始执行添加存储管理器组件操作")
        path = "/ugreen/v1/storage/overview/widget"
        request_data = {"type": type, "flags": flags}
        try:
            response = self.http.post(path, json=request_data)
            return response
        except Exception as e:
            log.error(f"在添加存储管理器组件过程中出现异常，异常信息: {e}")

    def get_widget_position(self, type):
        """
        根据组件类型获取组件的位置
        :param type: 组件类型  1：硬盘状态信息、2：存储空间状态信息、3：定时任务计划、4：硬盘性能监测、5：存储空间性能监测
        :return:组件当前的索引位置
        """
        if type not in (1, 2, 3, 4, 5):
            log.error(f"传入的组件类型参数 {type} 不合法")
            return None
        log.debug("开始执行根据组件类型获取组件的位置操作")
        widget_list = self.get_widget_list()
        log.info(f"获取到的组件列表信息为：{widget_list}")
        try:
            return next(index for index, widget in enumerate(widget_list) if widget.get("type") == type)
        except StopIteration:
            log.error("未找到该组件")
            return None
        finally:
            if not widget_list:
                log.info("组件列表为空")

    @check_response(ext="data", check=assert_message)
    def change_widget_position(self, type, index, number, flages):
        """
        改变小组件的顺序
        :param type: 组件类型  1：硬盘状态信息、2：存储空间状态信息、3：定时任务计划、4：硬盘性能监测、5：存储空间性能监测
        :param index: 移动前组件的序号
        :param number: 移动后组件的序号
        :param flages: 小组件配置 [1,2]、[0]
        :return:
        """
        log.debug("开始执行改变小组件的顺序操作")
        path = f"/ugreen/v1/storage/overview/widget/{index}"
        request_data = {"type": type, "index": index, "number": number, "flags": flages}
        try:
            response = self.http.post(path, json=request_data)
            return response
        except Exception as e:
            log.error(f"在改变小组件的顺序过程中出现异常，异常信息: {e}")

    @check_response(ext="data", check=assert_message)
    def delete_widget(self, index):
        """
        删除存储管理器组件
        :param index: 组件序号
        :return:
        """
        log.debug("开始执行删除存储管理器组件操作")
        path = f"/ugreen/v1/storage/overview/widget/{index}/delete"
        try:
            response = self.http.post(path)
            return response
        except Exception as e:
            log.error(f"在删除存储管理器组件过程中出现异常，异常信息: {e}")

    def delete_widgets(self):
        """
        删除存储管理器所有组件
        :return:
        """
        log.debug("开始执行删除存储管理器所有组件")
        widget_list = self.get_widget_list()
        log.info(f"待删除的组件信息为：{widget_list}")
        if widget_list:
            for index, widget in enumerate(widget_list):
                try:
                    self.delete_widget(0)
                    time.sleep(0.1)
                    log.info(f"成功删除存储管理器组件，组件序号为: {index}")
                except Exception as e:
                    log.error(f"在删除存储管理器组件 {index} 过程中出现异常，异常信息: {e}")
                    break
        else:
            log.info("组件列表为空，无需删除")

    def get_unused_disk_name(self):
        """
        从列表中获取未使用的硬盘名称列表
        :return: 未使用硬盘的名称列表，如果没有未使用硬盘则返回None
        """
        log.debug("开始执行获取未使用的硬盘名称操作")
        dev_name_list = []
        try:
            log.debug("开始获取所有硬盘信息列表")
            disk_info_list = self.get_disk_list()
            log.info(f"获取到的所有硬盘列表信息为：{disk_info_list}")
            assert isinstance(disk_info_list, list), f"传入的参数必须是列表类型,当前类型为：{type(disk_info_list)}"
            for index, disk in enumerate(disk_info_list):
                log.debug(f"正在检查磁盘信息列表中的第 {index + 1} 个元素是否符合要求")
                if not isinstance(disk, dict):
                    raise ValueError("列表中的元素必须是字典类型")
                usage = disk.get('usage')
                if usage is None:
                    raise KeyError(f"硬盘信息字典中缺少 'usage' 属性，当前硬盘信息为: {disk}")
                if usage == 0:
                    dev_name = disk.get('dev_name')
                    if dev_name:
                        log.info(f"发现未使用硬盘，名称为: {dev_name}，将其添加到结果列表中")
                        dev_name_list.append(dev_name)
                    else:
                        log.warning(f"磁盘 {disk} 的 'dev_name' 属性值为None，无法添加到结果列表")
            if not dev_name_list:
                log.info("未找到未使用的硬盘，返回None")
                return None
            log.info(f"成功获取未使用的硬盘名称列表，包含 {len(dev_name_list)} 个元素，列表内容为: {dev_name_list}")
            return dev_name_list
        except Exception as e:
            log.error(f"在获取未使用的硬盘名称过程中出现异常，异常信息: {e}")
            raise

    def get_used_disk_name(self):
        """
        从列表中获取已使用的硬盘名称列表
        :return: 已使用硬盘的名称列表，如果没有已使用硬盘则返回None
        """
        log.info("开始执行获取已使用的硬盘名称操作")
        dev_name_list = []
        try:
            log.info("开始获取硬盘信息列表")
            disk_info_list = self.get_disk_list()
            log.info("正在验证传入的参数是否符合要求")
            assert isinstance(disk_info_list, list), "传入的参数必须是列表类型"
            for index, disk in enumerate(disk_info_list):
                log.info(f"正在检查磁盘信息列表中的第 {index + 1} 个元素是否符合要求")
                if not isinstance(disk, dict):
                    raise ValueError("列表中的元素必须是字典类型")
                usage = disk.get('usage')
                if usage is None:
                    raise KeyError(f"硬盘信息字典中缺少 'usage' 属性，当前硬盘信息为: {disk}")
                if usage == 1:
                    dev_name = disk.get('dev_name')
                    if dev_name:
                        log.info(f"发现已使用硬盘，名称为: {dev_name}，将其添加到结果列表中")
                        dev_name_list.append(dev_name)
                    else:
                        log.warning(f"磁盘 {disk} 的 'dev_name' 属性值为None，无法添加到结果列表")
            if not dev_name_list:
                log.info("未找到已使用的硬盘，返回None")
                return None
            log.info(f"成功获取已使用的硬盘名称列表，包含 {len(dev_name_list)} 个元素，列表内容为: {dev_name_list}")
            return dev_name_list
        except Exception as e:
            log.error(f"在获取未使用的硬盘名称过程中出现异常，异常信息: {e}")
            raise

    def check_pool_status(self, timeout=600, status=0, wait_interval=20):
        """
        检查存储池状态是否符合要求

        参数:
        - timeout: 检查的超时时间，单位为秒，默认值为600秒，表示在这个时间内持续检查存储池状态。
        - status: 期望的存储池状态值，默认值为0，用于与实际获取的存储池状态进行对比。
        - wait_interval: 每次检查后等待的时间间隔，单位为秒，默认值为20秒，即每次检查完后等待该时长后再次检查。

        返回值:
        - 如果在超时时间内所有存储池的状态都达到期望的状态值，则返回True；否则抛出TimeoutError异常或者其他相应的异常（根据实际出现的问题）。
        """
        try:
            start_time = time.time()
            while time.time() - start_time < timeout:
                pool_list = self.get_pool_list()
                if pool_list:
                    # 记录当前获取到的存储池列表信息，方便排查问题
                    log.info(f"当前存储池列表信息为：{pool_list}")
                    all_status_matched = True
                    for pool in pool_list:
                        current_status = pool.get('status')
                        if current_status != status:
                            all_status_matched = False
                            # 记录每个不符合要求的存储池状态以及等待后重试的信息
                            log.info(f"存储池 {pool} 状态为 {current_status}，等待 {wait_interval} 秒后重试")
                    if all_status_matched:
                        log.info(f"所有存储池状态均满足要求，状态值为 {status}")
                        return True
                # 按照设定的等待时间间隔进行等待，然后再次检查
                time.sleep(wait_interval)
            # 如果超时时间内存储池状态一直未全部满足要求，则抛出超时异常，并记录超时的具体时长信息
            elapsed_time = time.time() - start_time
            raise TimeoutError(f"在规定时间（{timeout} 秒）内存储池状态不满足要求，已耗时 {elapsed_time} 秒")
        except requests.RequestException as e:
            # 处理网络请求相关异常，例如连接问题、请求超时等，记录详细信息
            log.error(f"在获取存储池状态时出现网络请求相关异常，异常信息: {e}")
            raise
        except ValueError as e:
            # 处理可能的数据解析等相关异常，比如获取的存储池数据格式不符合预期导致无法获取状态值等情况
            log.error(f"在解析存储池状态数据时出现异常，异常信息: {e}")
            raise
        except Exception as e:
            log.error(f"在获取存储池状态过程中出现未知异常，异常信息: {e}")
            raise

    def check_volume_status(self, timeout=600, status=0, wait_interval=20):
        """
        确认存储空间状态是否正常

        参数:
        - timeout: 检查的超时时间，单位为秒，默认值为600秒，表示在这个时间范围内持续检查存储空间状态。
        - status: 期望的存储空间状态值，默认值为0，用于与实际获取的存储空间状态进行对比。
        - wait_interval: 每次检查后等待的时间间隔，单位为秒，默认值为10秒，即每次检查完后等待该时长后再次检查。

        返回值:
        - 如果在超时时间内所有检查的存储空间状态都达到期望的状态值，则返回True，表示存储空间状态正常；否则抛出TimeoutError异常或者其他相应的异常（根据实际出现的问题），说明存储空间状态未能满足要求。
        """
        try:
            # 记录检查存储空间状态操作开始的日志
            log.debug(f"开始检查存储空间状态，超时时间设置为{timeout}秒，期望状态值为{status}，等待间隔为{wait_interval}秒")
            start_time = time.time()
            while time.time() - start_time < timeout:
                # 获取存储池列表并记录详细信息，方便排查是否获取数据环节出现问题
                log.debug("正在获取存储池列表信息，用于检查存储空间状态...")
                res = self.get_pool_list()
                log.info(f"成功获取存储池列表信息：{res}")
                volumes = res[0].get("volumes")
                if volumes:
                    log.info(f"获取到的存储池列表信息为：{volumes}")
                    all_status_matched = True
                    for volume in volumes:
                        volume_name = volume.get("name")
                        current_status = volume.get('status')
                        if current_status != status:
                            all_status_matched = False
                            # 记录每个不符合要求的存储空间的名称、当前状态以及等待重试的信息
                            log.info(f"存储空间{volume_name}的状态为{current_status}，与期望状态{status}不符，等待{wait_interval}秒后重试")
                        if all_status_matched:
                            # 记录所有存储空间状态都符合要求的日志，并返回True
                            log.info("所有存储空间状态均符合要求，检查通过")
                            return True
                else:
                    log.warning("获取到的存储池列表中不包含存储空间信息，可能存在问题，继续检查...")
                # 按照设定的等待时间间隔进行等待，然后再次检查
                time.sleep(wait_interval)
            # 如果超时时间内存储空间状态一直未全部满足要求，则抛出超时异常，并记录超时的具体时长信息
            elapsed_time = time.time() - start_time
            raise TimeoutError(f"在规定时间（{timeout} 秒）内未能获取到所有存储空间都有效的状态信息，已耗时 {elapsed_time} 秒")
        except requests.RequestException as e:
            # 处理网络请求相关异常，例如连接问题、请求超时等，记录详细的异常信息和相关上下文
            log.error(f"在获取存储池列表以检查存储空间状态时出现网络请求相关异常，异常信息:{e}")
            raise
        except KeyError as e:
            # 处理可能的数据解析相关异常，比如获取的存储池列表或存储空间数据格式不符合预期，缺少相应的键等情况
            log.error(f"在解析存储池列表或存储空间数据时出现键值异常，异常信息: {e}")
            raise
        except Exception as e:
            # 在其他未知异常情况下，记录详细的异常信息以及相关上下文，方便后续排查问题
            log.error(f"在检查存储空间状态过程中出现未知异常，异常信息:{e}")
            raise

    @retry_func(max_retries=30, retry_interval=10)
    def get_pool_name_list(self):
        """
        获取存储池名称列表信息
        :return: 存储池名称列表，如果获取过程出现问题则抛出相应异常
        """
        log.debug("开始执行获取存储池名称列表信息操作，进入 get_pool_name_list 方法")
        try:
            pool_info = []
            # 获取存储池列表信息
            pool_list = self.get_pool_list()
            # 验证传入的参数是否为列表类型
            if not isinstance(pool_list, list):
                raise TypeError("self.get_pool_list() 返回的结果不是列表类型，不符合要求")

            for index, pool in enumerate(pool_list):
                # 验证元素是否为字典类型
                if not isinstance(pool, dict):
                    raise TypeError(f"存储池信息列表中的第 {index + 1} 个元素不是字典类型，不符合要求")

                name = pool.get('name')
                if name is None:
                    log.warning(f"存储池信息列表中的第 {index + 1} 个元素缺少 'name' 属性，无法添加到结果列表")
                else:
                    pool_info.append(name)

            if not pool_info:
                log.warning("遍历完存储池列表后，未获取到有效的存储池名称，返回空列表")
            else:
                log.info(f"成功获取存储池名称列表，包含 {len(pool_info)} 个元素，具体列表内容为: {pool_info}")
            return pool_info
        except TypeError as e:
            log.error(f"参数类型不符合要求，出现类型错误: {e}")
            raise
        except KeyError as e:
            log.error(f"在访问存储池元素属性时出现键错误，可能属性不存在: {e}")
            raise
        except Exception as e:
            log.error(f"在获取存储池名称列表过程中出现其他未知异常，异常信息: {e}")
            raise

    def get_pool_info_by_poolname(self, pool_name):
        """
        根据存储池名称返回存储池详细信息
        :return:
        """
        log.debug(f"开始执行获取存储池名称为 {pool_name} 的详细信息操作，进入 get_pool_info_by_poolname 方法")
        try:
            pool_list = self.get_pool_list()
            log.info(f"成功获取存储池列表,列表信息为：{pool_list}")
            for pool in pool_list:
                if pool.get("name") == pool_name:
                    log.info(f"成功获取存储池名称为 {pool_name} 的详细信息，详细信息为：{pool}")
                    return pool
            log.warning(f"未找到存储池名称为 {pool_name} 的存储池信息")
            return None
        except Exception as e:
            log.error(f"在获取存储池名称列表过程中出现其他未知异常，异常信息: {e}")
            raise

    @retry_func(max_retries=10, retry_interval=10)
    def get_volume_devices(self, pool_name):
        """
        获取存储空间devices列表信息，暂时只支持一个存储池的情况
        :return: 存储空间名称列表，如果获取过程出现问题则抛出相应异常
        """
        log.debug(f"开始执行获取存储池名称为 {pool_name} 的存储空间devices列表信息操作，进入 get_volume_devices 方法")
        try:
            volume_info = []
            pool_info = self.get_pool_info_by_poolname(pool_name)
            volume_list = pool_info.get("volumes")

            # 验证传入的参数是否为列表类型
            if not isinstance(volume_list, list):
                raise TypeError("volume_list返回的结果不是列表类型，不符合要求")

            for index, volume in enumerate(volume_list):
                # 验证元素是否为字典类型
                if not isinstance(volume, dict):
                    raise TypeError(f"存储池信息列表中的第 {index + 1} 个元素不是字典类型，不符合要求")

                name = volume.get('device')
                if name is None:
                    log.warning(f"存储池信息列表中的第 {index + 1} 个元素缺少 'name' 属性，无法添加到结果列表")
                else:
                    log.info(f"存储池信息列表中的第 {index + 1} 个元素包含 'name' 属性，值为 {name}，将其添加到结果列表")
                    volume_info.append(name)

            if not volume_info:
                log.info("遍历完存储池列表后，未获取到有效的存储池名称，返回空列表")
            else:
                log.info(f"成功获取存储池名称列表，包含 {len(volume_info)} 个元素，具体列表内容为: {volume_info}")
            return volume_info
        except TypeError as e:
            log.error(f"参数类型不符合要求，出现类型错误: {e}", exc_info=True)
            raise
        except KeyError as e:
            log.error(f"在访问存储池元素属性时出现键错误，可能属性不存在: {e}", exc_info=True)
            raise
        except Exception as e:
            log.error(f"在获取存储池名称列表过程中出现其他未知异常，异常信息: {e}", exc_info=True)
            raise

    def wait_for_pool_deletion(self, timeout=360, interval=20):
        """
        等待并确认存储池删除成功，设置合理的超时时间和轮询间隔。

        参数:
        - timeout: 等待存储池删除成功的超时时间，单位为秒，默认值为120秒，可根据实际情况调整。
        - interval: 检查存储池是否删除成功的轮询间隔时间，单位为秒，默认值为10秒，可根据实际情况调整。

        返回值:
        - 如果在超时时间内存储池全部成功删除，则无返回值；若超时则抛出TimeoutError异常。
        """
        start_time = time.time()
        while time.time() - start_time < timeout:
            pool_info = self.get_pool_name_list()
            if not pool_info:
                log.info("存储池名称列表为空，确认存储池删除成功")
                return
            log.info(f"存储池尚未全部删除，等待 {interval} 秒后再次检查...")
            time.sleep(interval)
        log.error("等待存储池删除超时，可能存在存储池未成功删除的情况，请手动检查")
        raise TimeoutError("等待存储池删除超时")

    @check_response(ext="data", check=assert_message)
    def creat_pool(self):
        """
        创建存储池，组件raid1
        :return: 返回创建存储池操作对应的响应对象，如果出现异常则抛出相应异常
        """
        log.debug("开始执行创建存储池操作，进入 creat_pool 方法")
        try:
            pool_name_list = self.get_pool_name_list()
            if pool_name_list:
                self.delete_pool_info()
            disk_list = self.get_unused_disk_name()
            if not disk_list:
                log.warning("未获取到未使用的硬盘名称列表，无法创建存储池，直接返回 None")
                return None
            else:
                if len(disk_list) < 2:
                    log.error("获取到的未使用硬盘名称数量不足2个，无法创建raid1存储池，至少需要2个硬盘，请检查磁盘状态")
                    raise ValueError("创建raid1存储池需要至少2个未使用的硬盘")

            path = "/ugreen/v1/storage/pool/create"
            x_curpass_token = login.get_curpass_token()
            headers = {"x-curpass-token": x_curpass_token}
            json_data = {
                "disks": [f"{disk_list[0]}", f"{disk_list[1]}"],
                "level": "raid1",
                "disk_check": False
            }
            log.info(f"构造创建存储池的请求体数据，具体内容如下:path{path}, headers: {headers}, json_data: {json_data}")
            response = self.http.post(path, json=json_data, headers=headers)
            return response
        except ValueError as e:
            log.error(f"参数验证出现问题，导致无法创建存储池: {e}")
            raise
        except KeyError as e:
            log.error(f"在构造请求体数据时出现键错误，可能键名拼写有误: {e}")
            raise
        except Exception as e:
            log.error(f"在执行创建存储池操作过程中出现其他未知异常，异常信息: {e}")
            raise

    def delete_pool_info(self, timeout=120, interval=10):
        """
        删除所有存储池
        :return:
        """
        log.debug("开始执行删除所有存储池操作，进入 delete_pool_info 方法")
        # 获取存储池名称列表
        log.debug("调用 self.get_pool_name_list() 方法获取存储池名称列表")
        pool_info = self.get_pool_name_list()
        if not pool_info:
            log.info("存储池名称列表为空，无需删除存储池，直接返回")
            return
        log.info(f"成功获取存储池名称列表，包含 {len(pool_info)} 个元素，具体列表内容为: {pool_info}")
        path = "/ugreen/v1/storage/pool/delete"
        try:
            # 获取用于设置请求头的 x-curpass-token
            log.debug("获取 x-curpass-token 用于设置请求头")
            x_curpass_token = login.get_curpass_token()
            headers = {"x-curpass-token": x_curpass_token, "x-cloud-token": x_curpass_token}
            log.info(f"设置请求头信息，headers: {headers}")

            # 存储发送请求失败的存储池名称列表
            failed_pools = []
            for index, pool in enumerate(pool_info):
                data = {"name": pool}
                log.info(f"正在处理第 {index + 1} 个存储池，准备发送删除请求，请求数据为: {data}")
                try:
                    response = self.http.post(path, json=data, headers=headers)
                except Exception as e:
                    log.error(f"发送删除存储池 {pool} 的请求时出现异常，异常信息: {e}")
                    failed_pools.append(pool)
                    continue
            if failed_pools:
                log.error(f"以下存储池删除请求发送失败: {failed_pools}，请检查相关问题")
                raise RuntimeError("部分存储池删除请求发送失败")
            log.debug("所有存储池删除请求已发送完毕")
            # 等待并确认存储池删除成功，设置合理的超时时间和轮询间隔
            self.wait_for_pool_deletion(timeout=timeout, interval=interval)
        except Exception as e:
            log.error(f"在执行删除所有存储池操作过程中出现异常，异常信息: {e}")
            raise

    def get_disk_status(self, disk_name, status):
        """
        根据硬盘名称及状态名称从硬盘列表获取硬盘各种状态
        :param disk_name: 要查询使用状态的硬盘名称。
        :param status: 状态的名称，比如：activate、is_support_ihm
        :return如果在磁盘列表中找到对应硬盘名称的记录，返回其使用状态；若未找到，则返回None。
        """
        log.debug(f"开始执行获取硬盘 {disk_name} 使用状态操作，进入 get_disk_use_status 方法")
        try:
            disk_list = self.get_disk_list()
        except requests.RequestException as e:
            log.error(f"在函数 {__name__}.get_disk_use_status 中获取磁盘列表时出现网络请求相关异常，硬盘名称为 {disk_name}，异常信息: {e}")
            raise
        except KeyError as e:
            log.error(f"在函数 {__name__}.get_disk_use_status 中解析磁盘列表数据时出现键值异常，硬盘名称为 {disk_name}，可能数据格式有误，异常信息: {e}")
            raise
        except Exception as e:
            log.error(f"在函数 {__name__}.get_disk_use_status 中获取磁盘列表时出现其他未知异常，硬盘名称为 {disk_name}，异常信息: {e}")
            raise

        # 遍历磁盘列表，查找与传入硬盘名称匹配的磁盘记录，获取其使用状态
        log.debug(f"开始从{disk_list}中获取硬盘{disk_name}的{status}状态")
        for disk in disk_list:
            device_name = disk.get("dev_name")
            disk_status = disk.get(status)
            if device_name == disk_name:
                return disk_status
        log.warning(f"在{disk_list}中未找到硬盘名称为 {disk_name} 的使用状态")
        return None

    @check_response(ext="data.status", check=assert_message)
    def get_disk_runningState(self, disk):
        """
        获取硬盘运行状况
        :param disk: 硬盘名称 /dev/sda
        :return:硬盘运行状态
        """
        request_path = "/ugreen/v1/storage/disk/runningState"
        request_params = {"disk": disk}
        log.debug(f"准备获取硬盘 {disk} 的运行状况，请求路径为 {request_path}，请求参数为 {request_params}")
        try:
            response = self.http.get(request_path, request_params)
        except requests.RequestException as e:
            log.error(f"在获取硬盘 {disk} 的运行状况时出现网络请求相关异常，异常信息: {e}")
            raise
        except Exception as e:
            log.error(f"在获取硬盘 {disk} 的运行状况过程中出现其他未知异常，异常信息: {e}")
            raise
        return response

    @check_response(ext="data", check=assert_message)
    def get_disk_attribute(self, disk):
        """
        获取硬盘的详细信息 - 基本属性
        参数:disk： 硬盘名称，格式如 /dev/sda，用于指定要获取基本属性信息的目标硬盘。
        返回值:正常情况下，返回值为调用相关接口后获取到的经过 @check_response 装饰器处理的响应数据，具体格式和内容取决于接口的实际返回情况。
        """
        path = "/ugreen/v1/storage/disk/attribute"
        request_params = {"disk": disk}
        # 记录请求前的准备信息，方便排查问题，使用 debug 级别，可根据日志配置灵活查看
        log.debug(f"准备获取硬盘 {disk} 的基本属性信息，请求路径为 {path}，请求参数为 {request_params}")
        try:
            response = self.http.get(path, request_params)
            return response
        except requests.RequestException as e:
            log.error(f"在获取硬盘 {disk} 的基本属性信息时出现网络请求相关异常，异常信息: {e}")
            raise
        except Exception as e:
            log.error(f"在获取硬盘 {disk} 的基本属性信息过程中出现其他未知异常，异常信息: {e}")
            raise

    @check_response(ext="data", check=assert_message)
    def get_disk_benchmark_info(self, disk):
        """
        获取硬盘的获取FIO检测结果
        参数:disk: 硬盘名称，格式如 /dev/sda，用于指定要获取硬盘的获取FIO检测结果的目标硬盘。
        返回值:在正常情况下，返回值是调用相关接口后，经过 @check_response 装饰器处理的响应数据。需根据实际情况进行相应处理。
        """
        # 请求路径，明确表示是获取硬盘 S.M.A.R.T. 信息的接口路径
        path = "/ugreen/v1/storage/disk/benchmark/info"
        # 请求参数，用于指定要查询的硬盘名称
        request_params = {"disk": disk}
        # 使用 debug 级别记录请求前的准备信息，方便调试时查看请求详情
        log.debug(f"准备获取硬盘 {disk} 的FIO检测结果，请求路径为 {path}，请求参数为 {request_params}")
        try:
            response = self.http.get(path, request_params)
            # 使用 info 级别记录获取到的响应的关键信息，如状态码和部分关键数据示例（可按需调整）
            return response
        except requests.RequestException as e:
            log.error(f"在获取硬盘 {disk} 的FIO检测结果时出现网络请求相关异常，异常信息: {e}")
            raise
        except Exception as e:
            log.error(f"在获取硬盘 {disk} 的FIO检测结果过程中出现其他未知异常，异常信息: {e}")
            raise

    def get_disk_color(self, name, max_retries=2,wait_time=10):
        """
        # 设置最大重试次数，这里设置为2次，包含首次尝试，可根据实际情况调整
        SSH登录服务器通过串口获取亮灯颜色。

        参数:
        - name (str): 设备名称，取值应为对应的可获取亮灯颜色的设备名称，目前已知可取值为 'disk1'、'disk2'、'disk3'、'disk4'、'network_stat'、'power'。
        返回值:
        - str: 返回从服务器串口获取到的对应设备亮灯颜色相关信息，若获取过程中出现异常，则根据具体的异常处理逻辑返回相应的错误提示信息或者抛出异常。
        """

        retry_count = 0
        while retry_count < max_retries:
            log.info(f"开始第 {retry_count + 1} 次执行获取设备 {name} 亮灯颜色的操作")
            try:
                # 使用with语句管理SSH客户端的生命周期，确保连接在使用完后自动关闭
                with self.create_ssh_connection() as ssh_client:
                    log.debug(f"成功建立 SSH 连接，准备执行获取亮灯颜色命令，目标设备: {name}")
                    commond = f"cat /sys/class/leds/{name}/state"
                    try:
                        stdin, stdout, stderr = ssh_client.exec_command(commond, timeout=10)  # 设置合适的超时时间，可调整
                        exit_status = stdout.channel.recv_exit_status()  # 获取命令执行的退出状态码，用于判断是否正常执行
                        if exit_status != 0:
                            error_msg = stderr.read().decode().strip()
                            log.error(
                                f"第 {retry_count + 1} 次执行获取亮灯颜色命令时出现错误，命令: {commond}，错误信息: {error_msg}，退出状态码: {exit_status}")
                            return f"执行获取亮灯颜色命令失败，错误信息: {error_msg}"
                        output = stdout.read().decode().strip()
                        if not output:  # 判断获取结果是否为空
                            if retry_count < max_retries - 1:
                                log.warning(f"第 {retry_count + 1} 次获取到的亮灯颜色信息为空，将进行重试，目标设备: {name}")
                                retry_count += 1
                                time.sleep(wait_time)  # 等待10秒后重试
                                continue  # 直接进行下一次循环，即重试
                            else:
                                log.error(f"多次尝试后获取的亮灯颜色信息仍为空，目标设备: {name}")
                                return f"获取的亮灯颜色信息为空，请检查相关设备及系统配置"
                        # 这里可以添加对输出格式的验证逻辑，假设亮灯颜色信息格式类似 "color:r:g:b"，示例验证如下
                        if "color:" not in output:
                            log.warning(f"获取到的亮灯颜色信息格式不符合预期，实际获取: {output}")
                            return f"获取的亮灯颜色信息格式不正确，实际获取: {output}"
                        log.debug(f"成功获取设备 {name} 的亮灯颜色信息: {output}")
                        return output
                    except paramiko.SSHException as e:
                        log.error(f"SSH 命令执行出现 SSH 相关异常，命令: {commond}，异常信息: {str(e)}")
                        return f"执行获取亮灯颜色命令时出现 SSH 相关异常: {str(e)}"
                    except socket.timeout as e:
                        log.error(f"执行获取亮灯颜色命令超时，命令: {commond}，超时时间设置为 10 秒，异常信息: {str(e)}")
                        return f"执行获取亮灯颜色命令超时，请检查网络连接或服务器响应情况"
                    except Exception as e:
                        log.error(f"执行获取亮灯颜色命令出现未知异常，命令: {commond}，异常信息: {str(e)}")
                        return f"执行获取亮灯颜色命令时出现未知异常: {str(e)}"
            except Exception as e:
                log.error(f"在创建 SSH 连接过程中出现异常，导致无法获取亮灯颜色，异常信息: {str(e)}")
                return f"创建 SSH 连接出现异常，无法获取亮灯颜色: {str(e)}"
            finally:
                log.info(f"完成第 {retry_count + 1} 次获取设备 {name} 亮灯颜色的操作")

    @check_response(ext="data", check=assert_message)
    def start_fio_check(self, disk, x_curpass_token=None):
        """
        启动FIO读写性能检测
        参数:
        - disk: 硬盘名称，格式如 /dev/sda，用于指定要进行 FIO 读写性能检测的目标硬盘。
        - x_curpass_token: 可选参数，用于设置请求头中的认证令牌信息（具体根据实际业务逻辑确定其作用），若未提供该参数，可能使用默认的认证方式（具体取决于相关实现）。
        返回值:在正常情况下，返回值是调用相关接口后，经过 @check_response 装饰器处理的响应数据。
        """
        # 构造请求路径，明确表示是启动硬盘 FIO 读写性能检测的接口路径
        path = "/ugreen/v1/storage/disk/benchmark/start"
        # 构造请求体数据，包含要检测的硬盘名称
        request_data = {"disk": disk}
        # 构造请求头信息，设置相关认证令牌（根据实际情况确定具体作用）
        request_headers = {"x-curpass-token": x_curpass_token, "x-cloud-token": x_curpass_token}
        # 使用 debug 级别记录请求前的准备信息，方便调试时查看请求详情
        log.debug(f"准备启动硬盘 {disk} 的 FIO 读写性能检测，请求路径为 {path}，请求体数据为 {request_data}，请求头信息为 {request_headers}")
        try:
            response = self.http.post(path, json=request_data, headers=request_headers)
            # 使用 info 级别记录获取到的响应的关键信息，如状态码和部分关键数据示例（可按需调整）
            return response
        except requests.RequestException as e:
            log.error(f"在启动硬盘 {disk} 的 FIO 读写性能检测时出现网络请求相关异常，异常信息: {e}")
            raise
        except KeyError as e:
            log.error(f"在构造请求数据或解析响应数据时出现键值异常，可能数据格式有误，异常信息: {e}")
            raise
        except Exception as e:
            log.error(f"在启动硬盘 {disk} 的 FIO 读写性能检测过程中出现其他未知异常，异常信息: {e}")
            raise

    @check_response(ext="data", check=assert_message)
    def stop_fio_check(self, disk):
        """
        停止FIO读写性能检测
        参数:
        - disk: 硬盘名称，格式如 /dev/sda，用于指定要进行 FIO 读写性能检测的目标硬盘。
        返回值:在正常情况下，返回值是调用相关接口后，经过 @check_response 装饰器处理的响应数据。
        """
        # 构造请求路径，明确表示是停止硬盘 FIO 读写性能检测的接口路径
        path = "/ugreen/v1/storage/disk/benchmark/stop"
        # 构造请求体数据，包含要检测的硬盘名称
        request_data = {"disk": disk}
        # 使用 debug 级别记录请求前的准备信息，方便调试时查看请求详情
        log.debug(f"准备停止硬盘 {disk} 的 FIO 读写性能检测，请求路径为 {path}，请求体数据为 {request_data}")
        try:
            response = self.http.post(path, json=request_data)
            return response
        except requests.RequestException as e:
            log.error(f"在停止硬盘 {disk} 的 FIO 读写性能检测时出现网络请求相关异常，异常信息: {e}")
            raise
        except KeyError as e:
            log.error(f"在构造请求数据或解析响应数据时出现键值异常，可能数据格式有误，异常信息: {e}")
            raise
        except Exception as e:
            log.error(f"在停止硬盘 {disk} 的 FIO 读写性能检测过程中出现其他未知异常，异常信息: {e}")
            raise

    @check_response(ext="data", check=assert_message)
    def get_fio_result(self, disk):
        """
        获取FIO检测进展，确认检测已完成
        参数:- disk: 硬盘名称，格式如 /dev/sda，用于指定要获取其 FIO 检测进展情况的目标硬盘。
        返回值:- 在正常情况下，返回值是调用相关接口后，经过 @check_response(ext="data", check=assert_message) 装饰器处理的响应数据。
        """
        # 构造获取FIO检测结果的接口请求路径
        path = "/ugreen/v1/storage/disk/benchmark/running"
        # 设置请求参数，将硬盘名称作为参数传递给服务器，以便获取对应硬盘的检测进展信息
        request_params = {"disk": disk}
        # 使用 debug 级别记录请求前的准备信息，方便调试时查看请求详情
        log.debug(f"准备获取硬盘 {disk} 的 FIO 检测结果，请求路径为 {path}，请求参数为 {request_params}")
        try:
            response = self.http.get(path, request_params)
            return response
        except requests.RequestException as e:
            log.error(f"在获取硬盘 {disk} 的 FIO 检测结果时出现网络请求相关异常，异常信息: {e}")
            raise
        except KeyError as e:
            log.error(f"在解析返回的检测结果数据时出现键值异常，可能数据格式有误，异常信息: {e}")
            raise
        except ValueError as e:
            log.error(f"在处理返回的检测结果数据时出现值异常，可能涉及数据类型转换等问题，异常信息: {e}")
            raise
        except Exception as e:
            log.error(f"在获取硬盘 {disk} 的 FIO 检测结果过程中出现其他未知异常，异常信息: {e}")
            raise

    @check_response(ext="data", check=assert_message)
    def start_smart_check(self, disk, type=0):
        """
        启动S.M.A.R.T.检测
        参数:
        - disk: 硬盘名称，格式如 /dev/sda，用于指定要进行 S.M.A.R.T. 检测的目标硬盘。
        - type: 检测类型选择参数，取值为 0 表示快速检测，取值为 1 表示全面检测，用于告知服务器执行何种模式的 S.M.A.R.T. 检测操作。
        返回值:
        - 在正常情况下，返回值是调用相关接口后，经过 @check_response(ext="data", check=assert_message) 装饰器处理的响应数据。具体取决于业务逻辑中的异常处理设定），调用者需根据实际情况进行相应处理。
        """
        # 定义启动S.M.A.R.T.检测的接口请求路径
        request_path = "/ugreen/v1/storage/disk/smart/start"
        # 构造请求体数据，包含硬盘名称和检测类型信息，以便服务器知晓检测目标与方式
        request_data = {"disk": disk, "type": type}
        # 使用 debug 级别记录请求前的准备信息，方便调试及排查问题
        log.debug(f"准备发起启动硬盘 {disk} 的 S.M.A.R.T. 检测请求，请求路径为 {request_path}，请求体数据为 {request_data}")
        try:
            # 发起POST请求，向服务器发送启动S.M.A.R.T.检测的请求
            response = self.http.post(request_path, json=request_data)
            return response
        except requests.RequestException as e:
            # 捕获网络请求相关异常，记录详细错误信息并抛出异常让调用者知晓问题
            log.error(f"在启动硬盘 {disk} 的 S.M.A.R.T. 检测过程中出现网络请求相关异常，异常信息: {e}")
            raise
        except KeyError as e:
            # 捕获数据格式相关异常，可能是返回数据格式不符合预期，记录错误信息并抛出异常
            log.error(f"在构造请求数据或解析响应数据时出现键值异常，可能数据格式有误，异常信息: {e}")
            raise
        except TypeError as e:
            # 捕获数据类型相关异常，提示数据类型方面可能存在问题，记录错误信息并抛出异常
            log.error(f"在处理请求数据或解析响应数据时出现数据类型异常，异常信息: {e}")
            raise
        except Exception as e:
            # 捕获其他未知异常，记录详细信息以便后续排查问题，同时抛出异常
            log.error(f"在启动硬盘 {disk} 的 S.M.A.R.T. 检测过程中出现其他未知异常，异常信息: {e}")
            raise

    @check_response(ext="data", check=assert_message)
    def get_smart_info(self, disk="/dev/sdb"):
        """
        获取S.M.A.R.T.检测列表信息
        参数:
        - disk: 硬盘名称，默认值为 /dev/sdb，用于指定要获取其 S.M.A.R.T. 检测列表信息的目标硬盘。调用者可根据实际需求传入不同的硬盘名称。
        返回值:
        - 在正常情况下，返回值是调用相关接口后，经过 @check_response(ext="data", check=assert_message) 装饰器处理的响应数据。调用者需根据实际情况进行相应处理。
        """
        # 构造获取S.M.A.R.T.检测列表信息的接口请求路径
        request_path = "/ugreen/v1/storage/disk/smart/info"
        # 设置请求参数，将硬盘名称传递给服务器，以便服务器知晓要查询哪个硬盘的检测信息
        request_params = {"disk": disk}
        # 使用 debug 级别记录请求前的准备信息，方便调试时查看请求详情
        log.debug(f"准备获取硬盘 {disk} 的 S.M.A.R.T. 检测列表信息，请求路径为 {request_path}，请求参数为 {request_params}")
        try:
            response = self.http.get(request_path, request_params)
            return response
        except requests.RequestException as e:
            log.error(f"在获取硬盘 {disk} 的 S.M.A.R.T. 检测列表信息时出现网络请求相关异常，异常信息: {e}")
            raise
        except KeyError as e:
            log.error(f"在解析返回的 S.M.A.R.T. 检测列表信息数据时出现键值异常，可能数据格式有误，异常信息: {e}")
            raise
        except ValueError as e:
            log.error(f"在处理返回的 S.M.A.R.T. 检测列表信息数据时出现值异常，可能涉及数据类型转换等问题，异常信息: {e}")
            raise
        except Exception as e:
            log.error(f"在获取硬盘 {disk} 的 S.M.A.R.T. 检测列表信息过程中出现其他未知异常，异常信息: {e}")
            raise

    @check_response(ext="data", check=assert_message)
    def start_ihm_check(self, disk="/dev/sdd"):
        """
        启动IHM检测
        参数:
        - disk: 硬盘名称，格式如 /dev/sdd，用于指定要进行IHM检测的目标硬盘。
        返回值:
        - 在正常情况下，返回值是调用相关接口后，经过 @check_response(ext="data", check=assert_message) 装饰器处理的响应数据。具体取决于业务逻辑中的异常处理设定），调用者需根据实际情况进行相应处理。
        """
        # 定义启动S.M.A.R.T.检测的接口请求路径
        request_path = "/ugreen/v1/storage/disk/ihm/start"
        # 构造请求体数据，包含硬盘名称和检测类型信息，以便服务器知晓检测目标与方式
        request_data = {"disk": disk, "type": {"isTrusted": True}}
        # 使用 debug 级别记录请求前的准备信息，方便调试及排查问题
        log.debug(f"准备发起启动硬盘 {disk} 的IHM检测请求，请求路径为 {request_path}，请求体数据为 {request_data}")
        try:
            # 发起POST请求，向服务器发送启动IHM检测的请求
            response = self.http.post(request_path, json=request_data)
            return response
        except requests.RequestException as e:
            # 捕获网络请求相关异常，记录详细错误信息并抛出异常让调用者知晓问题
            log.error(f"在启动硬盘 {disk} 的IHM检测过程中出现网络请求相关异常，异常信息: {e}")
            raise
        except KeyError as e:
            # 捕获数据格式相关异常，可能是返回数据格式不符合预期，记录错误信息并抛出异常
            log.error(f"在构造请求数据或解析响应数据时出现键值异常，可能数据格式有误，异常信息: {e}")
            raise
        except TypeError as e:
            # 捕获数据类型相关异常，提示数据类型方面可能存在问题，记录错误信息并抛出异常
            log.error(f"在处理请求数据或解析响应数据时出现数据类型异常，异常信息: {e}")
            raise
        except Exception as e:
            # 捕获其他未知异常，记录详细信息以便后续排查问题，同时抛出异常
            log.error(f"在启动硬盘 {disk} 的IHM检测过程中出现其他未知异常，异常信息: {e}")
            raise

    @check_response(ext="data", check=assert_message)
    def get_ihm_info(self, disk="/dev/sdd"):
        """
        获取IHM检测列表信息
        参数:
        - disk: 硬盘名称，默认值为 /dev/sdb，用于指定要获取其IHM检测列表信息的目标硬盘。调用者可根据实际需求传入不同的硬盘名称。
        返回值:
        - 在正常情况下，返回值是调用相关接口后，经过 @check_response(ext="data", check=assert_message) 装饰器处理的响应数据。调用者需根据实际情况进行相应处理。
        """
        # 构造获取IHM检测列表信息的接口请求路径
        request_path = "/ugreen/v1/storage/disk/ihm/info"
        # 设置请求参数，将硬盘名称传递给服务器，以便服务器知晓要查询哪个硬盘的检测信息
        request_params = {"disk": disk}
        # 使用 debug 级别记录请求前的准备信息，方便调试时查看请求详情
        log.debug(f"准备获取硬盘 {disk} 的IHM检测列表信息，请求路径为 {request_path}，请求参数为 {request_params}")
        try:
            response = self.http.get(request_path, request_params)
            return response
        except requests.RequestException as e:
            log.error(f"在获取硬盘 {disk} 的IHM检测列表信息时出现网络请求相关异常，异常信息: {e}")
            raise
        except KeyError as e:
            log.error(f"在解析返回的IHM检测列表信息数据时出现键值异常，可能数据格式有误，异常信息: {e}")
            raise
        except ValueError as e:
            log.error(f"在处理返回的IHM检测列表信息数据时出现值异常，可能涉及数据类型转换等问题，异常信息: {e}")
            raise
        except Exception as e:
            log.error(f"在获取硬盘 {disk} 的IHM检测列表信息过程中出现其他未知异常，异常信息: {e}")
            raise

    @check_response(ext="data.result", check=assert_message)
    def get_detection_list(self, disk):
        """
        获取S.M.A.R.T.检测结果
        参数:
        - disk: 硬盘名称，格式如 /dev/sda，用于指定要获取其 S.M.A.R.T. 检测结果的目标硬盘。
        返回值:
        - 在正常情况下，返回值是调用相关接口后，经过 @check_response(ext="data.result", check=assert_message) 装饰器处理的响应数据。调用者需根据实际情况进行相应处理。
        """
        # 构造获取S.M.A.R.T.检测结果的接口请求路径
        request_path = "/ugreen/v1/storage/disk/detection/list"
        # 设置请求参数，将硬盘名称传递给服务器，以便获取对应硬盘的检测结果信息
        request_params = {"disk": disk}
        # 使用 debug 级别记录请求前的准备信息，方便调试时查看请求详情
        log.debug(f"准备获取硬盘 {disk} 的 S.M.A.R.T. 检测结果，请求路径为 {request_path}，请求参数为 {request_params}")
        try:
            response = self.http.get(request_path, request_params)
            return response
        except requests.RequestException as e:
            log.error(f"在获取硬盘 {disk} 的 S.M.A.R.T. 检测结果时出现网络请求相关异常，异常信息: {e}")
            raise
        except KeyError as e:
            log.error(f"在解析返回的 S.M.A.R.T. 检测结果数据时出现键值异常，可能数据格式有误，异常信息: {e}")
            raise
        except ValueError as e:
            log.error(f"在处理返回的 S.M.A.R.T. 检测结果数据时出现值异常，可能涉及数据类型转换等问题，异常信息: {e}")
            raise
        except Exception as e:
            log.error(f"在获取硬盘 {disk} 的 S.M.A.R.T. 检测结果过程中出现其他未知异常，异常信息: {e}")
            raise

    @check_response(ext="data.result", check=assert_message)
    def get_disk_position_endtime(self, disk):
        """
        获取硬盘定位剩余时长
        参数:
        - disk: 硬盘名称，格式如 /dev/sda，用于指定要获取其定位剩余时长信息的目标硬盘。
        返回值:
        - 在正常情况下，返回值是调用相关接口后，经过 @check_response(ext="data.result", check=assert_message) 装饰器处理的响应数据。调用者需根据实际情况进行相应处理。
        """
        # 定义获取硬盘定位剩余时长的接口请求路径
        request_path = "/ugreen/v1/storage/disk/position/endtime"
        # 构造请求体数据，将硬盘名称传递给服务器，以便服务器知晓针对哪个硬盘获取剩余时长信息
        request_data = {"disk": disk}
        # 使用 debug 级别记录请求前的准备信息，方便调试时查看请求详情
        log.debug(f"准备获取硬盘 {disk} 的定位剩余时长信息，请求路径为 {request_path}，请求体数据为 {request_data}")
        try:
            response = self.http.post(request_path, json=request_data)
            return response
        except requests.RequestException as e:
            log.error(f"在获取硬盘 {disk} 的定位剩余时长信息时出现网络请求相关异常，异常信息: {e}")
            raise
        except KeyError as e:
            log.error(f"在构造请求数据或解析响应数据时出现键值异常，可能数据格式有误，异常信息: {e}")
            raise
        except TypeError as e:
            log.error(f"在处理请求数据或解析响应数据时出现数据类型异常，异常信息: {e}")
            raise
        except Exception as e:
            log.error(f"在获取硬盘 {disk} 的定位剩余时长信息过程中出现其他未知异常，异常信息: {e}")
            raise

    @check_response(ext="data", check=assert_message)
    def start_disk_position(self, disk, time=60):
        """
        开始硬盘定位
        参数:
        - disk: 硬盘名称，格式如 /dev/sda，用于指定要进行定位操作的目标硬盘。
        - time: 定位操作的时长，单位为秒，默认值为 60 秒，用于告知服务器执行硬盘定位操作的预计时长（具体作用依实际业务逻辑和接口要求而定）。
        返回值:
        - 在正常情况下，返回值是调用相关接口后，经过 @check_response(ext="data", check=assert_message) 装饰器处理的响应数据。调用者需根据实际情况进行相应处理。
        """
        # 构造开始硬盘定位操作的接口请求路径
        request_path = "/ugreen/v1/storage/disk/position"
        # 构造请求体数据，包含要定位的硬盘名称以及定位时长信息，以便服务器知晓操作详情
        request_data = {"disk": disk, "time": time}
        # 使用 debug 级别记录请求前的准备信息，方便调试时查看请求详情
        log.debug(f"准备发起对硬盘 {disk} 的定位操作请求，请求路径为 {request_path}，请求体数据为 {request_data}")
        try:
            response = self.http.post(request_path, json=request_data)
            return response
        except requests.RequestException as e:
            log.error(f"在发起硬盘 {disk} 的定位操作时出现网络请求相关异常，异常信息: {e}")
            raise
        except KeyError as e:
            log.error(f"在构造请求数据或解析响应数据时出现键值异常，可能数据格式有误，异常信息: {e}")
            raise
        except TypeError as e:
            log.error(f"在处理请求数据或解析响应数据时出现数据类型异常，异常信息: {e}")
            raise
        except Exception as e:
            log.error(f"在发起硬盘 {disk} 的定位操作过程中出现其他未知异常，异常信息: {e}")
            raise

    @check_response(ext="data", check=assert_message)
    def restore_disk_position(self, disk):
        """
        还原硬盘定位
        参数:
        - disk: 硬盘名称，格式如 /dev/sda，用于指定要进行还原定位操作的目标硬盘。
        返回值:
        - 在正常情况下，返回值是调用相关接口后，经过 @check_response(ext="data", check=assert_message) 装饰器处理的响应数据。调用者需根据实际情况进行相应处理。
        """
        # 构造还原硬盘定位操作的接口请求路径
        request_path = "/ugreen/v1/storage/disk/position/restore"
        # 构造请求体数据，将硬盘名称传递给服务器，以便服务器知晓针对哪个硬盘进行还原操作
        request_data = {"disk": disk}
        # 使用 debug 级别记录请求前的准备信息，方便调试时查看请求详情
        log.debug(f"准备发起对硬盘 {disk} 的定位还原操作请求，请求路径为 {request_path}，请求体数据为 {request_data}")
        try:
            response = self.http.post(request_path, json=request_data)
            return response
        except requests.RequestException as e:
            log.error(f"在发起硬盘 {disk} 的定位还原操作时出现网络请求相关异常，异常信息: {e}")
            raise
        except KeyError as e:
            log.error(f"在构造请求数据或解析响应数据时出现键值异常，可能数据格式有误，异常信息: {e}")
            raise
        except TypeError as e:
            log.error(f"在处理请求数据或解析响应数据时出现数据类型异常，异常信息: {e}")
            raise
        except Exception as e:
            log.error(f"在发起硬盘 {disk} 的定位还原操作过程中出现其他未知异常，异常信息: {e}")
            raise

    def wait_for_raid1_creation(self, timeout=300, interval=30):
        """
        等待并确认RAID1创建成功，根据设定的超时时间和轮询间隔进行检查。
        参数:
        - timeout: 等待RAID1创建成功的超时时间，单位为秒，默认值为300秒，可由调用者根据实际情况调整。
        - interval: 每次检查RAID1创建情况的轮询间隔时间，单位为秒，默认值为30秒，同样可按需调整。
        返回值:
        - 如果在超时时间内RAID1创建成功（通过检查存储池状态判断），则返回存储池信息列表；若超时则返回None，提示调用者手动检查RAID1创建情况。
        """
        start_time = time.time()
        # 记录开始等待RAID1创建成功的操作日志
        log.debug(f"开始等待RAID1创建成功，超时时间设置为{timeout}秒，轮询间隔时间设置为{interval}秒")
        while time.time() - start_time < timeout:
            pool_list = self.get_pool_list()
            if pool_list and pool_list[0].get("status") == 0:
                log.info(f"RAID1创建成功，当前存储池信息为：{pool_list}")
                return pool_list
            # 按照设定的轮询间隔时间等待后再次检查
            log.info(f"RAID1未创建成功，等待 {interval} 秒后再次检查...")
            time.sleep(interval)
        log.error("等待RAID1创建成功超时，请手动检查RAID1创建情况")
        return None

    def create_ssh_connection(self, max_retry_times=6, retry_interval=20):
        """
        创建 SSH 连接的函数，通过获取登录相关信息（主机名、用户名、密码），调用创建 SSH 客户端的函数来建立连接。
        :param: max_retry_times: 最大重试次数，默认为5次。
        :param: retry_interval: 重试间隔时间，默认为20秒。
        返回值:
        - 若成功创建 SSH 连接，返回对应的 SSH 客户端对象（具体类型取决于 create_ssh_client_as_root 函数的返回值定义）；
        - 若出现异常，根据异常处理机制进行相应反馈，可能抛出异常或者返回特定的错误提示信息（具体取决于具体的处理逻辑）。
        """
        host_name = login.hostname
        # 获取用户名，从Login实例中提取相应属性值
        user_name = login.username
        # 获取原始密码，从Login实例中提取相应属性值
        user_password = login.raw_password
        retry_count = 0
        while retry_count < max_retry_times:
            try:
                # 调用函数创建SSH连接，传入获取到的主机名、用户名和密码
                ssh_connection = create_ssh_client_as_root(host_name, user_name, user_password)
                return ssh_connection
            except AttributeError as e:
                log.error(f"在获取登录信息（主机名、用户名、密码）时出现属性不存在的异常，异常信息: {e}")
                raise
            except ConnectionError as e:
                if retry_count < max_retry_times - 1:
                    log.error(f"在创建 SSH 连接时出现网络连接相关异常，异常信息: {e}，将在 {retry_interval} 秒后进行第 {retry_count + 1} 次重试")
                    time.sleep(retry_interval)
                    retry_count += 1
                else:
                    log.error(f"已达到最大重试次数 {max_retry_times}，仍然出现网络连接相关异常，异常信息: {e}")
                raise
            except Exception as e:
                log.error(f"在创建 SSH 连接过程中出现其他未知异常，异常信息: {e}")
                raise

    def create_raid1(self, size=10):
        """
        创建RAID1

        参数:
        - size: 硬盘大小，单位为G，用于指定创建RAID1时相关硬盘的容量大小（具体根据创建逻辑确定其作用方式）。

        返回值:
        - 如果创建RAID1成功，返回相应的存储池信息（具体根据实际返回内容确定）；如果在创建过程中出现异常或者相关前置操作（如删除存储池、等待操作完成等）失败，则返回None或者抛出相应异常。
        """
        try:
            log.info("开始通过shell脚本创建RAID1")
            log.debug("创建RAID1前，先获取当前存储池信息，准备执行删除所有存储池操作")
            pool_info = self.get_pool_name_list()
            log.info(f"当前存在 {len(pool_info)} 个存储池，即将执行删除操作")

            log.debug("调用delete_pool_info方法删除所有存储池")
            self.delete_pool_info()

            log.debug("调用wait_for_pool_deletion方法等待确认存储池删除成功")
            self.wait_for_pool_deletion()

            log.info("开始创建RAID1，创建前先创建SSH连接")
            ssh_client = self.create_ssh_connection()
            if ssh_client is None:
                log.error("创建SSH连接失败，无法继续创建RAID1，请检查网络或SSH配置相关问题")
                raise ConnectionError("创建SSH连接失败")

            log.info(f"使用SSH连接，通过shell脚本创建RAID1，硬盘大小设置为{size}G")
            create_raid_with_shell(ssh_client, disk_size=size)

            log.info("确认RAID1创建成功，等待20秒后检查相关存储池信息")
            time.sleep(20)

            log.debug("调用wait_for_raid1_creation方法等待确认RAID1相关存储池创建完成")
            pool_info = self.wait_for_raid1_creation()
            if pool_info is None:
                log.warning("等待确认RAID1相关存储池创建完成超时或出现问题，返回None")
                return None

            return pool_info
        except requests.RequestException as e:
            # 处理网络请求相关异常，例如在删除存储池、获取存储池信息等涉及网络请求操作时可能出现的异常
            log.error(f"在创建RAID1过程中出现网络请求相关异常，异常信息: {e}")
            raise
        except TimeoutError as e:
            # 处理等待相关操作超时的异常，比如等待存储池删除、等待RAID1相关存储池创建完成超时等情况
            log.error(f"在创建RAID1过程中出现等待超时异常，异常信息: {e}")
            raise
        except Exception as e:
            # 捕获其他未知异常情况，记录详细信息方便后续排查
            log.error(f"在创建RAID1过程中出现未知异常，异常信息:{e}")
            raise

    @check_response(ext="data", check=assert_message)
    def replace_disk(self, pool_name, disks, replace_disk):
        """
        给指定的存储池替换硬盘
        :param target_pool_name: 目标存储池的名称
        :param disks: 替换的新硬盘名称，格式如 /dev/sda
        :param replace_disk: 要替换的旧硬盘名称，格式如 /dev/sda
        :return: 替换硬盘操作对应的响应对象
        """
        # 构造替换硬盘请求的路径
        path = "/ugreen/v1/storage/pool/replace"
        log.debug(f"准备发送硬盘替换请求，请求路径为: {path}")
        try:
            # 获取用于身份验证的令牌
            x_curpass_token = login.get_curpass_token()
            log.debug(f"成功获取 x_curpass_token，值为: {x_curpass_token}")
        except Exception as e:
            log.error(f"获取 x_curpass_token 时出现异常，异常信息: {e}")
            raise

        # 构造请求的数据体，包含存储池名称、新磁盘信息和要替换的磁盘
        request_data = {
            "name": pool_name,
            "disks": [disks],
            "replace_disk": replace_disk
        }
        log.info(f"构造的硬盘替换请求数据体为: {request_data}")
        headers = {"x-curpass-token": x_curpass_token, "x-cloud-token": x_curpass_token}
        try:
            # 发送 HTTP POST 请求执行硬盘替换操作
            response = self.http.post(path, json=request_data, headers=headers)
            return response
        except Exception as e:
            log.error(f"执行 HTTP POST 请求替换硬盘操作时出现异常，异常信息: {e}")
            raise

    @check_response(ext="data", check=assert_message)
    def creat_spare(self, raid_name, disks):
        """
        给存储池添加热备盘
        :param raid_name: 目标存储池的名称，格式如：/dev/md0
        :param disks: 添加的硬盘，格式如 /dev/sda
        :return: 添加热备盘操作对应的响应对象
        """
        # 构造替换硬盘请求的路径
        path = "/ugreen/v1/storage/spare/create"
        log.debug(f"准备发送添加热备盘请求，请求路径为: {path}")
        try:
            # 获取用于身份验证的令牌
            x_curpass_token = login.get_curpass_token()
            log.info(f"成功获取 x_curpass_token，值为: {x_curpass_token}")
        except Exception as e:
            log.error(f"获取 x_curpass_token 时出现异常，异常信息: {e}")
            raise

        # 构造请求的数据体，包含存储池名称、要替换的磁盘和新磁盘信息
        request_data = {"raid": raid_name, "disks": [disks]}
        log.debug(f"构造的添加热备盘请求数据体为: {request_data}")
        headers = {"x-curpass-token": x_curpass_token, "x-cloud-token": x_curpass_token}

        try:
            # 发送 HTTP POST 请求执行硬盘替换操作
            response = self.http.post(path, json=request_data, headers=headers)
            log.info("已成功发送添加热备盘请求，正在等待响应")
            return response
        except Exception as e:
            log.error(f"执行 HTTP POST 请求添加热备盘操作时出现异常，异常信息: {e}")
            raise

    @check_response(ext="data", check=assert_message)
    def delete_spare(self, raid_name, disk):
        """
        给存储池删除热备盘
        :param raid_name: 目标存储池的名称，格式如：/dev/md0
        :param disk: 添加的硬盘，格式如 /dev/sda
        :return: 添加热备盘操作对应的响应对象
        """

        # 构造替换硬盘请求的路径
        path = "/ugreen/v1/storage/spare/delete"
        log.debug(f"准备发送删除热备盘请求，请求路径为: {path}")
        # 构造请求的数据体，包含存储池名称、要替换的磁盘和新磁盘信息
        request_data = {"raid": raid_name, "disk": disk}
        log.debug(f"构造的删除热备盘请求数据体为: {request_data}")
        try:
            # 发送 HTTP POST 请求执行硬盘替换操作
            response = self.http.post(path, json=request_data)
            return response
        except Exception as e:
            log.error(f"执行 HTTP POST 请求删除热备盘操作时出现异常，异常信息: {e}")
            raise

    @check_response(ext="data", check=assert_message)
    def stop_use_disk(self, disk):
        """
        停用硬盘
        :param disk: 硬盘名称，格式如：/dev/sda
        :return:
        """
        # 构造替换硬盘请求的路径
        path = "/ugreen/v1/storage/disk/deactivate"
        log.debug(f"准备发送停用硬盘请求，请求路径为: {path}")

        try:
            # 获取用于身份验证的令牌
            x_curpass_token = login.get_curpass_token()
            log.debug(f"成功获取 x_curpass_token，值为: {x_curpass_token}")
        except Exception as e:
            log.error(f"获取 x_curpass_token 时出现异常，异常信息: {e}")
            raise

        # 构造请求的数据体，包含存储池名称、新磁盘信息和要替换的磁盘
        request_data = {
            "disk": disk,
            "password": x_curpass_token,  # 使用 x_curpass_token 作为密码
        }
        log.debug(f"构造的硬盘替换请求数据体为: {request_data}")
        headers = {"x-curpass-token": x_curpass_token, "x-cloud-token": x_curpass_token}

        try:
            # 发送 HTTP POST 请求执行硬盘替换操作
            response = self.http.post(path, json=request_data, headers=headers)
            return response
        except Exception as e:
            log.error(f"执行 HTTP POST 请求替换硬盘操作时出现异常，异常信息: {e}")
            raise

    @check_response(ext="data", check=assert_message)
    def start_use_disk(self, disk):
        """
        启用硬盘
        :param disk: 硬盘名称，格式如：/dev/sda
        :return:
        """
        # 构造替换硬盘请求的路径
        path = "/ugreen/v1/storage/disk/activate"
        log.debug(f"准备发送启用硬盘请求，请求路径为: {path}")

        # 构造请求的数据体，包含存储池名称、新磁盘信息和要替换的磁盘
        request_data = {"disk": disk}
        log.info(f"构造的启用硬盘请求数据体为: {request_data}")

        try:
            # 发送 HTTP POST 请求执行硬盘替换操作
            response = self.http.post(path, json=request_data)
            return response
        except Exception as e:
            log.error(f"执行 HTTP POST 请求替换硬盘操作时出现异常，异常信息: {e}")
            raise

    @check_response(ext="data", check=assert_message)
    def fix_pool(self, disk, pool):
        """
        修复存储池
        :param disk: 硬盘名称，格式如：/dev/sda
        :param pool: 存储池名称
        :return:
        """
        # 构造替换硬盘请求的路径
        path = "/ugreen/v1/storage/pool/fix"
        log.debug(f"准备发送修复存储池请求，请求路径为: {path}")

        try:
            # 获取用于身份验证的令牌
            x_curpass_token = login.get_curpass_token()
            log.debug(f"成功获取 x_curpass_token，值为: {x_curpass_token}")
        except Exception as e:
            log.error(f"获取 x_curpass_token 时出现异常，异常信息: {e}")
            raise

        # 构造请求的数据体，包含存储池名称、新磁盘信息和要替换的磁盘
        request_data = {
            "name": pool,
            "disks": [disk]
        }
        log.info(f"构造的修复存储池请求数据体为: {request_data}")
        headers = {"x-curpass-token": x_curpass_token, "x-cloud-token": x_curpass_token}

        try:
            # 发送 HTTP POST 请求执行硬盘替换操作
            response = self.http.post(path, json=request_data, headers=headers)
            return response
        except Exception as e:
            log.error(f"执行 HTTP POST 请求修复存储池操作时出现异常，异常信息: {e}")
            raise

    @check_response(ext="data", check=assert_message)
    def up_raid(self, pool, disk):
        """
        升级存储池RAID类型
        :param disk: 硬盘名称，格式如：/dev/sda
        :param pool: 存储池名称
        :return:
        """
        # 构造替换硬盘请求的路径
        path = "/ugreen/v1/storage/pool/up"
        log.debug(f"准备发送升级存储池RAID类型请求，请求路径为: {path}")

        try:
            # 获取用于身份验证的令牌
            x_curpass_token = login.get_curpass_token()
            log.debug(f"成功获取 x_curpass_token，值为: {x_curpass_token}")
        except Exception as e:
            log.error(f"获取 x_curpass_token 时出现异常，异常信息: {e}")
            raise

        # 构造请求的数据体，包含存储池名称、新磁盘信息和要替换的磁盘
        request_data = {
            "name": pool,
            "disks": [disk]
        }
        log.debug(f"构造的升级存储池RAID类型请求数据体为: {request_data}")
        headers = {"x-curpass-token": x_curpass_token, "x-cloud-token": x_curpass_token}

        try:
            # 发送 HTTP POST 请求执行硬盘替换操作
            response = self.http.post(path, json=request_data, headers=headers)
            return response
        except Exception as e:
            log.error(f"执行 HTTP POST 请求升级存储池RAID类型操作时出现异常，异常信息: {e}")
            raise

    @check_response(ext="data", check=assert_message)
    def extend_pool(self, pool, disk):
        """
        使用硬盘-给存储池扩容
        :param disk: 硬盘名称，格式如：/dev/sda
        :param pool: 存储池名称
        :return:
        """
        # 构造替换硬盘请求的路径
        path = "/ugreen/v1/storage/pool/ext"
        log.debug(f"准备发送使用硬盘-给存储池扩容请求，请求路径为: {path}")

        try:
            # 获取用于身份验证的令牌
            x_curpass_token = login.get_curpass_token()
            log.debug(f"成功获取 x_curpass_token，值为: {x_curpass_token}")
        except Exception as e:
            log.error(f"获取 x_curpass_token 时出现异常，异常信息: {e}")
            raise

        # 构造请求的数据体，包含存储池名称、新磁盘信息和要替换的磁盘
        request_data = {
            "name": pool,
            "disks": [disk]
        }
        log.debug(f"构造的使用硬盘-给存储池扩容请求数据体为: {request_data}")
        headers = {"x-curpass-token": x_curpass_token, "x-cloud-token": x_curpass_token}

        try:
            # 发送 HTTP POST 请求执行硬盘替换操作
            response = self.http.post(path, json=request_data, headers=headers)
            return response
        except Exception as e:
            log.error(f"执行 HTTP POST 请求使用硬盘-给存储池扩容操作时出现异常，异常信息: {e}")
            raise

    @check_response(ext="data", check=assert_message)
    def pool_scrub(self, pool):
        """
        存储池数据整理
        :param pool: 存储池名称 格式例如："pool1"
        :return:
        """
        # 构造替换硬盘请求的路径
        path = "/ugreen/v1/storage/pool/scrub"
        log.debug(f"准备发送存储池数据整理请求，请求路径为: {path}")
        # 构造请求的数据体，包含存储池名称、新磁盘信息和要替换的磁盘
        request_data = {"name": pool}
        log.debug(f"构造的存储池数据整理请求数据体为: {request_data}")
        try:
            # 发送 HTTP POST 请求执行硬盘替换操作
            response = self.http.post(path, json=request_data)
            return response
        except Exception as e:
            log.error(f"执行 HTTP POST 请求存储池数据整理操作时出现异常，异常信息: {e}")
            raise

    @check_response(ext="data", check=assert_message)
    def stop_pool_scrub(self, pool):
        """
        停止存储池数据整理
        :param pool: 存储池名称 格式例如："pool1"
        :return:
        """
        # 构造替换硬盘请求的路径
        path = "/ugreen/v1/storage/pool/scrub/stop"
        log.debug(f"准备发送停止存储池数据整理请求，请求路径为: {path}")
        # 构造请求的数据体，包含存储池名称、新磁盘信息和要替换的磁盘
        request_data = {"name": pool}
        log.debug(f"构造的停止存储池数据整理请求数据体为: {request_data}")
        try:
            # 发送 HTTP POST 请求执行硬盘替换操作
            response = self.http.post(path, json=request_data)
            return response
        except Exception as e:
            log.error(f"执行 HTTP POST 请求停止存储池数据整理操作时出现异常，异常信息: {e}")
            raise

    @check_response(ext="data", check=assert_message)
    def pool_scrub_edit(self, pool, data_time, interval=0, interval_unit=0):
        """
        编辑存储池数据整理计划
        :param pool: 存储池名称 格式例如："pool1"
        :param data_time: 编辑后的时间格式例如："2024-12-31 00:02:00" (大于当前时间）
        :param interval: 整理间隔时间，0表示单次、1表示每月1次，3表示每3个月1次，6表示每6个月1次
        :param interval_unit: 整理间隔时间单位，0为天，5为月，默认为0
        :return:
        """
        # 构造替换硬盘请求的路径
        path = "/ugreen/v1/storage/pool/scrub/edit"
        log.debug(f"准备发送编辑存储池数据整理计划请求，请求路径为: {path}")
        # 构造请求的数据体，包含存储池名称、新磁盘信息和要替换的磁盘
        request_data = {"pool_name": pool, "scheduled": {"first_run_datetime": data_time, "interval": interval,
                                                         "interval_unit": interval_unit}}
        log.debug(f"构造的编辑存储池数据整理计划请求数据体为: {request_data}")
        try:
            # 发送 HTTP POST 请求执行硬盘替换操作
            response = self.http.post(path, json=request_data)
            return response
        except Exception as e:
            log.error(f"执行 HTTP POST 请求编辑存储池数据整理计划操作时出现异常，异常信息: {e}")
            raise

    @check_response(ext="data", check=assert_message)
    def create_volume_withpool(self, pool, size, filesystem):
        """
        根据存储池创建存储空间
        :param pool: 存储池名称 示例："pool1"
        :param size: 存储空间大小 示例："100GB"
        :param filesystem: 文件系统类型 示例："btrfs" / "ext4"
        :return:
        """
        path = "/ugreen/v1/storage/volume/createWithPool"
        log.debug(f"准备发送创建存储空间请求，请求路径为: {path}")
        data = {"pool": pool, "storage": {"size": size, "filesystem": filesystem}}
        try:
            response = self.http.post(path, json=data)
            return response
        except Exception as e:
            log.error(f"执行 HTTP POST 请求根据存储池创建存储空间操作时出现异常，异常信息: {e}")
            raise

    @check_response(ext="data", check=assert_message)
    def get_pool_capacity(self, level, disks, operate_type=1):
        """
        获取存储池预估容量
        :param level: raid类型，示例raid0
        :param disks: 磁盘列表 示例：["/dev/nvme0n1","/dev/nvme1n1"]
        :param operate_type: 操作类型 示例：1
        :return:SSD缓存列表
        """
        path = "/ugreen/v1/storage/pool/capacity"
        params = {"level": level, "disks": disks, "operate_type": operate_type}
        log.debug(f"准备发送获取存储池预估容量请求，请求路径为: {path}")
        try:
            response = self.http.get(path, params=params)
            return response
        except Exception as e:
            log.error(f"执行 HTTP POST 请求获取存储池预估容量操作时出现异常，异常信息: {e}")
            raise

    @check_response(ext="data", check=assert_message)
    def check_disk_compatibility(self, disks):
        """
        检查硬盘兼容性
        :param disks: 磁盘列表 示例：["/dev/nvme0n1","/dev/nvme1n1"]
        :return:SSD缓存列表
        """
        path = "/ugreen/v1/storage/pool/capacity"
        data = {"disks": disks}
        log.debug(f"准备发送检查硬盘兼容性请求，请求路径为: {path}")
        try:
            response = self.http.post(path, json=data)
            return response
        except Exception as e:
            log.error(f"执行 HTTP POST 请求检查硬盘兼容性操作时出现异常，异常信息: {e}")
            raise

    @check_response(ext="data", check=assert_message)
    def create_cache_withpool(self, volume, cache_pool, size="50GB"):
        """
        创建SSD缓存
        :param volume: 存储空间信息，示例：{"device": "/dev/mapper/ug_2F6A7C_1720080527_pool1-volume2", "mount_point": "/volume2","filesystem": "btrfs"}
        :param size: 缓存空间大小 示例："100GB"
        :param cache_pool: 缓存池名称 示例："cachePool1"
        :return:
        """
        path = "/ugreen/v1/storage/cache/createWithPool"
        log.debug(f"准备发送创建SSD缓存请求，请求路径为: {path}")
        data = {"volume": volume, "mode": "ro", "size": size, "cache_pool": cache_pool}
        try:
            response = self.http.post(path, json=data)
            return response
        except Exception as e:
            log.error(f"执行 HTTP POST 请求创建SSD缓存操作时出现异常，异常信息: {e}")
            raise

    @check_response(ext="data", check=assert_message)
    def create_cache(self, volume, disks, level="raid0", size="50GB"):
        """
        创建SSD缓存
        :param level: raid等级，示例：raid0
        :param volume: 存储空间信息，示例：{"device": "/dev/mapper/ug_2F6A7C_1720080527_pool1-volume1", "mount_point": "/volume1", "filesystem": "ext4"}
        :param disks: 硬盘信息，示例：["/dev/nvme0n1", "/dev/nvme1n1"]
        :param size: 缓存空间大小 示例："100GB"
        :return:
        """
        path = "/ugreen/v1/storage/cache/create"
        log.debug(f"准备发送创建SSD缓存请求，请求路径为: {path}")

        try:
            # 获取用于身份验证的令牌
            x_curpass_token = login.get_curpass_token()
            log.info(f"成功获取 x_curpass_token，值为: {x_curpass_token}")
        except Exception as e:
            log.error(f"获取 x_curpass_token 时出现异常，异常信息: {e}")
            raise
        headers = {"x-curpass-token": x_curpass_token}
        data = {"mode": "ro", "level": level, "systemCapacity": "12.5MB",
                "volume": volume, "disks": disks, "size": size}
        try:
            response = self.http.post(path, json=data, headers=headers)
            return response
        except Exception as e:
            log.error(f"执行 HTTP POST 请求创建SSD缓存操作时出现异常，异常信息: {e}")
            raise

    import logging

    # 假设这里已经正确配置了logging模块，log是对应的日志记录器实例
    log = logging.getLogger(__name__)

    @check_response(ext="data", check=assert_message)
    def delete_cache_operation(self, pool_device, cache_name=None):
        """
        执行删除SSD缓存相关操作，可用于删除普通SSD缓存或移除特定存储空间的SSD缓存。
        参数:
        - type: raid类型，示例：0、删除单个存储空间的SSD缓存；1、删除整个SSD缓存
        - pool_device: 存储空间信息，示例：cachePool1
        - cache_name: 可选参数，缓存名称，示例：cacheVolume2。若不传该参数（即值为None），则执行删除普通SSD缓存操作；若传入具体的缓存名称，则执行移除对应存储空间SSD缓存操作。
        返回值:
        - 在正常情况下，返回值是调用相关接口后，经过 @check_response(ext="data", check=assert_message) 装饰器处理的响应数据，具体格式和内容取决于接口的实际返回情况。
        """
        path = "/ugreen/v1/storage/cache/delete"
        log.debug(f"准备发送删除SSD缓存请求，请求路径为: {path}")
        if cache_name is None:
            data = {"type": 1, "pool_device": pool_device}
        else:
            data = {"type": 0, "pool_device": pool_device, "cache_name": cache_name}
        try:
            response = self.http.post(path, json=data)
            return response
        except Exception as e:
            log.error(f"执行 HTTP POST 请求删除SSD缓存操作时出现异常，异常信息: {e}")
            raise

    @check_response(ext="data.result", check=assert_message)
    def get_cache_name(self):
        """
        获取SSD缓存名称
        :return:SSD缓存名称
        """
        path = "/ugreen/v1/storage/cache/name"
        log.debug(f"准备发送获取SSD缓存名称请求，请求路径为: {path}")
        try:
            response = self.http.get(path)
            return response
        except Exception as e:
            log.error(f"执行 HTTP POST 请求获取SSD缓存名称操作时出现异常，异常信息: {e}")
            raise

    @check_response(ext="data", check=assert_message)
    def get_cache_list(self, pool_name):
        """
        获取SSD缓存列表
        :param pool_name: 存储池名称 示例：pool1
        :return:SSD缓存列表
        """
        path = "/ugreen/v1/storage/cache/list"
        params = {"name": pool_name}
        log.debug(f"准备发送获取SSD缓存列表请求，请求路径为: {path}")
        try:
            response = self.http.get(path, params=params)
            return response
        except Exception as e:
            log.error(f"执行 HTTP POST 请求获取SSD缓存列表操作时出现异常，异常信息: {e}")
            raise

    @check_response(ext="data.available", check=assert_message)
    def get_cache_availableDisks(self, pool_name):
        """
        查询添加缓存池有哪些可用硬盘
        :param pool_name: 存储池名称 示例：pool1
        :return:可以作为缓存的硬盘列表
        """
        path = "/ugreen/v1/storage/cache/availableDisks"
        params = {"poolName": pool_name}
        log.debug(f"准备发送查询添加缓存池有哪些可用硬盘请求，请求路径为: {path}")
        try:
            response = self.http.get(path, params=params)
            return response
        except Exception as e:
            log.error(f"执行 HTTP POST 请求查询添加缓存池有哪些可用硬盘操作时出现异常，异常信息: {e}")
            raise

    @check_response(ext="data", check=assert_message)
    def set_pool_setting(self, mode=0, bitmap=1):
        """
        设置存储池高级设置内容
        :param mode: 性能选项 0：用户读写优先  1：RAID同步优先
        :param bitmap: 快速修复 0：关闭    1：开启
        :return:
        """
        path = "/ugreen/v1/storage/pool/setting/set"
        data = {"raid_speed_limit": {"mode": mode}, "bitmap": {"enable": bitmap}, "space_reclamation": {}}
        try:
            response = self.http.post(path, json=data)
            return response
        except Exception as e:
            log.error(f"执行 HTTP POST 请求创建卷操作时出现异常，异常信息: {e}")
            raise

    @check_response(ext="data", check=assert_message)
    def get_pool_setting(self):
        """
        获取存储池高级设置内容
        :return:
        """
        path = "/ugreen/v1/storage/pool/setting/get"
        try:
            response = self.http.get(path)
            return response
        except Exception as e:
            log.error(f"执行 HTTP POST 请求创建卷操作时出现异常，异常信息: {e}")
            raise

    @check_response(ext="data", check=assert_message)
    def set_volume_setting(self, device, percent=10):
        """
        设置存储空间设置内容
        :param device:  "device=/dev/mapper/ug_220E17_1734664715_pool1-volume1"
        :param percent: 报警比例，默认10%
        :return:
        """
        path = "/ugreen/v1/storage/volume/setting"
        data = {"device": device, "capacity_notify": {"percent": percent}}
        try:
            response = self.http.post(path, json=data)
            return response
        except Exception as e:
            log.error(f"执行 HTTP POST 请求创建卷操作时出现异常，异常信息: {e}")
            raise

    @check_response(ext="data.capacity_notify", check=assert_message)
    def get_volume_setting(self, device):
        """
        获取存储空间设置内容
        :param device:  "device=/dev/mapper/ug_220E17_1734664715_pool1-volume1"
        :return:
        """
        path = "/ugreen/v1/storage/volume/setting"
        params = {"device": device}
        try:
            response = self.http.get(path, params=params)
            return response
        except Exception as e:
            log.error(f"执行 HTTP GET 请求获取存储空间设置内容时出现异常，异常信息: {e}")
            raise

    @check_response(ext="data", check=assert_message)
    def get_volume_spaceUsage(self, pool, volume):
        """
        获取存储空间使用情况
        :param pool:  存储池名称
        :param volume: 存储空间名称
        :return:
        """
        path = "/ugreen/v1/storage/volume/spaceUsage"
        params = {"poolName": pool, "volumeName": volume}
        try:
            response = self.http.get(path, params=params)
            return response
        except Exception as e:
            log.error(f"执行 HTTP GET 请求获取存储空间使用情况时出现异常，异常信息: {e}")
            raise

    @check_response(ext="data", check=assert_message)
    def delete_volume(self, volume_name):
        """
        删除存储池空间
        :param volume_name: 存储空间名称，格式如："/dev/mapper/ug_220E17_1734664715_pool1-volume1"
        :return:
        """
        path = "/ugreen/v1/storage/volume/delete"
        log.debug(f"准备发送删除存储池空间请求，请求路径为: {path}")

        try:
            # 获取用于身份验证的令牌
            x_curpass_token = login.get_curpass_token()
            log.info(f"成功获取 x_curpass_token，值为: {x_curpass_token}")
        except Exception as e:
            log.error(f"获取 x_curpass_token 时出现异常，异常信息: {e}")
            raise

        # 构造请求的数据体，包含存储池名称、新磁盘信息和要替换的磁盘
        request_data = {"name": volume_name}
        log.debug(f"构造的删除存储池空间请求数据体为: {request_data}")
        headers = {"x-curpass-token": x_curpass_token, "x-cloud-token": x_curpass_token}

        try:
            # 发送 HTTP POST 请求执行删除存储池空间操作
            response = self.http.post(path, json=request_data, headers=headers)
            return response
        except Exception as e:
            log.error(f"执行 HTTP POST 请求删除存储池空间时出现异常，异常信息: {e}")
            raise

    @check_response(ext="data", check=assert_message)
    def volume_grow(self, device, size):
        """
        给存储空间扩容
        :param device:  "device=/dev/mapper/ug_220E17_1734664715_pool1-volume1"
        :param size: 扩容的大小，示例：”10GB“
        :return:
        """
        log.debug("开始给存储空间扩容")
        path = "/ugreen/v1/storage/volume/grow"
        data = {"name": device, "extsize": size}
        try:
            response = self.http.post(path, json=data)
            return response
        except Exception as e:
            log.error(f"执行 HTTP POST 请求创建卷操作时出现异常，异常信息: {e}")
            raise

    @check_response(ext="data", check=assert_message)
    def get_extStorage_list(self):
        """
        获取外部存储列表（暂时固定未USB，后续可能使用其他类型外部存储）
        :return:外部存储列表
        """
        log.debug("开始获取外部存储列表")
        path = "/ugreen/v1/storage/extStorage/list"
        try:
            response = self.http.get(path)
            return response
        except Exception as e:
            log.error(f"执行 HTTP GET 请求获取外部存储列表时出现异常，异常信息: {e}")
            raise

    @check_response(ext="data", check=assert_message)
    def get_extStorage_setting(self):
        """
        获取外部存储高级设置信息
        :return:外部存储高级设置信息
        """
        log.debug("开始获取外部存储高级设置信息")
        path = "/ugreen/v1/storage/extStorage/setting/get"
        try:
            response = self.http.get(path)
            return response
        except Exception as e:
            log.error(f"执行 HTTP GET 请求获取外部存储高级设置信息时出现异常，异常信息: {e}")
            raise

    @check_response(ext="data", check=assert_message)
    def remove_extStorage(self, dev_name):
        """
        删除外部存储设备
        :param dev_name: 外部存储设备名称，示例："/dev/sdb"
        :return:
        """
        log.debug("开始删除外部存储设备")
        path = "/ugreen/v1/storage/extStorage/setting/set"
        request_data = {"device": dev_name}
        try:
            response = self.http.post(path, json=request_data)
            return response
        except Exception as e:
            log.error(f"执行 HTTP GET 请求删除外部存储设备时出现异常，异常信息: {e}")
            raise

    def remount_usb(self, mount_point):
        """
        重新挂载U盘
        :param mount_point: 示例："/mnt/@usb/sdb1"
        :return:
        """
        try:
            # 检查挂载点是否存在，如果不存在则创建
            if not os.path.exists(mount_point):
                os.makedirs(mount_point)
            # 使用subprocess模块执行挂载命令
            subprocess.check_call(["mount", "-t", "vfat", "/dev/sdb1", mount_point])
            log.info("U盘重新挂载成功")
        except subprocess.CalledProcessError as e:
            log.error(f"重新挂载U盘时出错:{e}")
        except Exception as e:
            log.error(f"发生其他错误:{e}")
            raise

    @check_response(ext="data", check=assert_message)
    def set_extStorage_setting(self, delay_allocation=True, disable_usb_storage=False, normal_user_can_access=True):
        """
        设置外部存储高级设置信息
        :param delay_allocation: 延迟分配
        :param disable_usb_storage: 是否禁用USB存储
        :param normal_user_can_access: 普通用户是否可以访问
        :return:
        """
        log.debug("开始设置外部存储高级设置信息")
        path = "/ugreen/v1/storage/extStorage/setting/set"
        request_data = {"delay_allocation": delay_allocation, "disable_usb_storage": disable_usb_storage,
                        "normal_user_can_access": normal_user_can_access}
        try:
            response = self.http.post(path, json=request_data)
            return response
        except Exception as e:
            log.error(f"执行 HTTP GET 请求获取外部存储高级设置信息时出现异常，异常信息: {e}")
            raise

    @check_response(ext="data", check=assert_message)
    def get_extStorage_files(self, usb_name):
        """
        获取外部存储文件信息
        :param usb_name: 外部存储挂载信息，示例："/mnt/@usb/sdb1"
        :return:
        """
        log.debug(f"开始获取外部存储设备{usb_name}的文件信息")
        path = "/ugreen/v2/filemgr/getDirFileListV2"
        request_data = {"limit": 2000, "page": 1, "is_shield_recycle": False, "permission": 0, "data_type": 0,
                        "left_no_page_show": False, "left_count": 5000, "sort_type": 1, "reverse": False,
                        "path": usb_name}
        try:
            response = self.http.post(path, json=request_data)
            return response
        except Exception as e:
            log.error(f"执行 HTTP GET 请求获取获取外部存储文件信息时出现异常，异常信息: {e}")
            raise


if __name__ == "__main__":
    token = login.login()
    a = DiskApi(token)
    disks = a.get_used_disk_name() if a.get_used_disk_name() else a.get_unused_disk_name()
    name = Fake.fake_name()
    a.add_disk_cron_task(name, disks)
    id = a.get_disk_cron_list()[0]["cron_id"]
    a.delete_disk_cron_task(id)
